#ifndef _EB0_SLIDESHOW_H_
#define _EB0_SLIDESHOW_H_

#include <EB0/Prereq.h>
#include <EB0/States/GameState.h>
#include <SFML/Graphics.hpp>
#include <string>
#include <vector>

// A slideshow is a collection of images to be traversed
// The user either has to wait a set amount of time per image or skip to the next on key press
// Each picture defines a duration and whether or not it is skippable
// A duration of 0.0f or less indicates the slide must be manually changed

// As a suggestion, slideshows should load the next image during the fade out
// And then preload the first image before the slideshow begins...
// The fade-in image could sit and wait until the load has been completed before continuing
// Only one image should be in memory at a time

// Actually, I need not even have mFading then - just mPendingSlide
// If mPendingSlide != UINT_MAX
// ... if mPendingSlide == mCurrentSlide
// ... ... Fade-in current slide, set mPendingSlide = UINT_MAX when complete
// ... else
// ... .... Fade-out current slide, set mCurrentSlide = mPendingSlide when complete
// else
// ... Update the current slide as per usual

// Commands to change the current slide will be ignored during transition

namespace EB0
{
namespace States
{
	class Slideshow abstract : public GameState
	{
		class Slide
		{
			friend class Slideshow;

		public:
			sf::Sprite* getSprite() const;
			bool isSkippable() const;

			bool fadeIn(float duration = 0.0f, float dt = 0.0f); // returns false when fading has completed
			bool fadeOut(float duration = 0.0f, float dt = 0.0f); // use elapsed, but reset it to 0.0f when done
			bool update(float dt = 0.0f); // returns false if the duration has been exceeded; but only if duration wasn't 0.0f

		private:
			Slide(char* filename, float duration = 0.0f, bool skippable = true);
			~Slide();

			static void loadThread(void* slide); //sf::Thread requires void* for all incoming data
			static void unloadThread(void* slide); // so we'll just have to convert it to Slide*

			void setElapsed(float elapsed); // to reset the elapsed time when manually switching slides

			std::string mFilename;
			sf::Image* mImage;
			sf::Sprite* mSprite;

			float mDuration;
			float mElapsed;
			bool mSkippable;
		};

	public:
		Slideshow();
		~Slideshow();

	protected:
		void loadSlideshow(Window::RenderWindow* window = 0);
		void createSlideshowScene(Window::RenderWindow* window = 0);
		void destroySlideshowScene(Window::RenderWindow* window = 0);
		void unloadSlideshow(Window::RenderWindow* window = 0);

		bool updateSlideshow(Window::RenderWindow* window = 0, float dt = 0.0f); // returns false if no more slides left
		bool stepForward(bool honourSkippable = false); // returns false if no more slides left
		bool jumpTo(unsigned short index, bool honourSkippable = false); // returns false if out of range (e.g. no slides left)

		void setFadeDuration(float duration = 0.0f); // 0.0f means no fade; fade-in + fade-out would take twice as long!
		float getFadeDuration() const;

		void createSlide(char* filename, float duration = 0.0f, bool skippable = true);
		void destroyAllSlides();

		virtual void onKeyRelease(Window::RenderWindow* window, const sf::Event::KeyEvent& key);

	private:
		typedef std::vector<Slide*> SlideVector;

		unsigned int mCurrentSlide;
		unsigned int mPendingSlide; //UINT_MAX when not transitioning

		SlideVector mSlides;
		Graphics::Renderable* mSlideshowRenderable;
		Window::Layer* mSlideshowLayer;
		float mFadeDuration;

		sf::Music* mTitleBGM;
	};
} // namespace States
}

#endif // _EB0_SLIDESHOW_H_